package cn.zhx.xa.bi.mq;


import cn.zhx.xa.model.enums.ChartStatus;
import cn.zhx.xa.bi.manage.AiManage;
import cn.zhx.xa.bi.mapper.BiChartMapper;
import cn.zhx.xa.bi.service.BiChartService;
import cn.zhx.xa.bi.ws.WebSocketServer;
import cn.zhx.xa.model.entity.BiChart;
import cn.zhx.xa.model.vo.bi.BiVo;
import cn.zhx.xa.model.vo.common.ResultCodeEnum;
import cn.zhx.xa.service.exception.BusinessException;
import cn.zhx.xa.utils.AuthContextUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.rabbitmq.client.Channel;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class BiMessageConsumer {

    @Resource
    private BiChartMapper biChartMapper;

    @Resource
    private BiChartService biChartService;

    @Resource
    private AiManage aiManage;

    @Resource
    private WebSocketServer webSocketServer;



    /**
     * @param message     表示接收到的消息内容 (这里接收的是图表的id)
     * @param channel     表示与RabbitMQ服务器之间的通信通道。通过该通道，你可以与RabbitMQ进行交互，如确认收到消息、拒绝消息等。
     * @param deliveryTag 表示消息的传递标签。每个传送的消息都会被分配一个唯一的delivery tag，用于标识该消息。通过delivery tag，你可以在需要时对消息进行确认、拒绝、重新投递等操作。
     */
    //ackMode = "MANUAL" 手动确认消息
    @SneakyThrows // 忽略异常
    @RabbitListener(queues = BiMqConstant.BI_QUEUE_NAME, ackMode = "MANUAL")
    public void receiveMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        log.info("receiveMessage message = {}", message);

        if (StringUtils.isBlank(message)) {
            /**
             * 拒签消息，设置消息重回队列中
             * deliveryTag: 消息投递号
             * true: 是否可以一次拒签多条消息
             * true: 拒签后消息是否重回队列，不放回消息则会放到死信队列
             */
            channel.basicNack(deliveryTag, false, false);
            throw new BusinessException(ResultCodeEnum.MESSAGE_EMPTY);
        }

        long chartId = Long.parseLong(message);
        BiChart biChart = biChartMapper.selectById(chartId);
        if (biChart == null) {
            channel.basicNack(deliveryTag, false, false);
            throw new BusinessException(ResultCodeEnum.CHART_EMPTY);
        }

        // 先修改图表任务状态为 “执行中”。等执行成功后，修改为 “已完成”、保存执行结果；
        // 执行失败后，状态修改为 “失败”，记录任务失败信息。
        BiChart updateChart = new BiChart();
        updateChart.setId(chartId);
        updateChart.setChartStatus(ChartStatus.RUNNING.getValue());
        int b = biChartMapper.updateById(updateChart);
        if (b <= 0) {
            handleChartUpdateError(chartId, "更新图表状态失败");
            return;
        }

        // 发送请求
        String chartResult = aiManage.doChat(biChartService.constructUserInput(biChart));
        // 处理ai生成的数据
        BiVo biVo = biChartService.getOrganizeAiData(chartId,chartResult);
        String genChart = biVo.getGenChart();
        String genResult = biVo.getGenResult();
        biVo.setChartId(chartId);

        // 更新图表信息
        BiChart updateChartResult = new BiChart();
        updateChartResult.setId(chartId);
        updateChartResult.setGenChart(genChart);
        updateChartResult.setGenResult(genResult);
        updateChartResult.setChartStatus(ChartStatus.SUCCEED.getValue());
        int updateResult = biChartMapper.updateById(updateChartResult);
        if (updateResult <= 0) {
            handleChartUpdateError(chartId, "更新图表成功信息失败");
        }

        webSocketServer.sendToOne(biChart.getUserId().toString(),"图表生成成功");
        /**
         * 手动签收消息
         * deliveryTag: 消息投递号
         * true: 是否可以一次签收多条消息
         */
        channel.basicAck(deliveryTag, false);
    }

    /**
     * 死信队列
     */
    @SneakyThrows // 忽略异常
    @RabbitListener(queues = BiMqConstant.BI_DEAD_QUEUE_NAME, ackMode = "MANUAL")
    public void receiveDeadMessage(String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
        log.info("receiveDeadMessage message = {}", message);
        if (StringUtils.isEmpty(message)) {
            channel.basicAck(deliveryTag, false);
            throw new BusinessException(ResultCodeEnum.MESSAGE_EMPTY);
        }
        long chartId = Long.parseLong(message);
        BiChart chart =biChartMapper.selectById(chartId);
        if (chart == null) {
            // 如果找不到图表，记录错误并确认消息
            log.error("死信队列中的图表ID {} 不存在", chartId);
            channel.basicAck(deliveryTag, false);
            return;
        }
        handleChartUpdateError(chartId, "图表获取失败");
        channel.basicAck(deliveryTag, false);
    }

    //更新图表信息失败
    private void handleChartUpdateError(Long id, String execMessage) {
        log.error(execMessage);
        BiChart updateChart = new BiChart();
        updateChart.setId(id);
        updateChart.setExecMessage(execMessage);
        updateChart.setChartStatus(ChartStatus.FAILED.getValue());
        int i = biChartMapper.updateById(updateChart);
        if (i <= 0) {
            log.error(execMessage + "更新失败");
        }
        webSocketServer.sendToOne(AuthContextUtil.get().toString(),"图表生成失败");
    }

}
